/*
 * Copyright (c) 2022. China Mobile (SuZhou) Software Technology Co.,Ltd. All rights reserved.
 * Lakehouse is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

package com.chinamobile.cmss.lakehouse.dao;

import com.chinamobile.cmss.lakehouse.common.utils.KeyValue;
import com.chinamobile.cmss.lakehouse.dao.entity.HiveMetastoreConfigEntity;

import java.util.List;
import java.util.stream.Collectors;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

@Repository
@Transactional
public class HiveMetastoreConfigDao {

    @PersistenceContext
    private EntityManager entityManager;

    @Autowired
    private DataSourceProperties dataSourceProperties;

    public List<HiveMetastoreConfigEntity> findByTableConfigs(List<KeyValue<String, String>> tables) {
        List<String> findTables = tables.stream()
            .map(t -> String.format("('%s', '%s')", t.key(), t.value())).collect(Collectors.toList());
        String schemaDb = getMetadataDatabase();
        String queryStr = String.format("select * from hive.table_params where TBL_ID in "
                + "(select TBL_ID from hive.tbls join hive.dbs on hive.tbls.DB_ID=hive.dbs.DB_ID "
                + "where ((hive.dbs.NAME, hive.tbls.TBL_NAME) in (%s)))",
            String.join(",", findTables));
        String querySql = queryStr.replace("hive", schemaDb);
        Query query = entityManager.createNativeQuery(querySql, HiveMetastoreConfigEntity.class);
        return query.getResultList();
    }

    public List<Object> findChangeLog(String dbName, String tbName) {
        String db = "dbName";
        String tbl = "tbName";

        String queryStr =
            "select * from table_task_inf where table_task_inf.DB_NAME = :dbName and table_task_inf.TB_NAME = :tbName";
        Query query = entityManager.createNativeQuery(queryStr);

        query.setParameter(db, dbName);
        query.setParameter(tbl, tbName);
        return query.getResultList();
    }

    /**
     * Query database records
     *
     * @param dbName
     * @return
     */
    public List<Object> findDbChangeLog(String dbName) {
        String db = "dbName";

        String queryStr = "select * from hive_dbs where hive_dbs.NAME = :dbName";
        Query query = entityManager.createNativeQuery(queryStr);

        query.setParameter(db, dbName);
        return query.getResultList();
    }

    public void updateChangeLog(String taskId, String tbName, String submitUser, String dbName) {
        String queryStr =
            "update table_task_inf set table_task_inf.TASK_ID = :taskId, table_task_inf.CREATOR =:submitUser, "
                + "table_task_inf.CREATE_TIME= :nowTime, table_task_inf.TASK_TYPE = 0 where table_task_inf.DB_NAME=:dbName and table_task_inf.TB_NAME=:tbName";

        executeDML(taskId, tbName, submitUser, dbName, queryStr);
    }

    public void updateDbChangeLog(String submitUser, String dbName, String identifierUser) {
        String queryStr =
            "update hive_dbs set hive_dbs.UPDATOR =:submitUser, hive_dbs.DELETED= 1, hive_dbs.UPDATE_TIME = :nowTime, "
                + "hive_dbs.CUSTOMER_ID = :identifierUser where hive_dbs.NAME=:dbName";

        executeDbDML(submitUser, dbName, identifierUser, queryStr);
    }

    public void insertChangeLog(String taskId, String tbName, String submitUser, String dbName) {
        String queryStr =
            "insert into table_task_inf (ID, TASK_TYPE, TASK_ID, DB_NAME, TB_NAME, CREATOR, CREATE_TIME) values (null ,0, :taskId, :dbName, :tbName, :submitUser, :nowTime)";
        executeDML(taskId, tbName, submitUser, dbName, queryStr);
    }

    public void insertDbChangeLog(String submitUser, String dbName, String identifierUser) {
        String queryStr =
            "insert into hive_dbs (ID, CREATE_TIME, CREATOR, DELETED, DESCRIPTION, NAME, UPDATE_TIME, UPDATOR, CUSTOMER_ID) "
                + "values (null , :nowTime, :submitUser, 0, null, :dbName, :nowTime, :submitUser, :identifierUser)";
        executeDbDML(submitUser, dbName, identifierUser, queryStr);
    }

    private void executeDML(String taskId, String tbName, String submitUser, String dbName,
                            String queryStr) {
        int now = (int) (System.currentTimeMillis() / 1000);

        String tId = "taskId";
        String user = "submitUser";
        String currentTime = "nowTime";
        String db = "dbName";
        String tbl = "tbName";

        Query query = entityManager.createNativeQuery(queryStr);
        query.setParameter(tId, taskId);
        query.setParameter(user, submitUser);
        query.setParameter(currentTime, now);
        query.setParameter(db, dbName);
        query.setParameter(tbl, tbName);
        query.executeUpdate();
    }

    private void executeDbDML(String submitUser, String dbName, String identifierUser, String queryStr) {
        int now = (int) (System.currentTimeMillis() / 1000);

        String user = "submitUser";
        String currentTime = "nowTime";
        String db = "dbName";
        String custID = "identifierUser";

        Query query = entityManager.createNativeQuery(queryStr);
        query.setParameter(user, submitUser);
        query.setParameter(currentTime, now);
        query.setParameter(db, dbName);
        query.setParameter(custID, identifierUser);
        query.executeUpdate();
    }

    private String getMetadataDatabase() {
        String url = dataSourceProperties.getUrl();
        String hiveSchemaDbSuffix = "_hive_schema";
        return url.substring(url.lastIndexOf("/") + 1, url.lastIndexOf("?")) + hiveSchemaDbSuffix;
    }

    public void deleteChangeLog(String dbName) {
        String db = "dbName";

        String queryStr = "delete from table_task_inf where table_task_inf.DB_NAME = :dbName";
        Query query = entityManager.createNativeQuery(queryStr);

        query.setParameter(db, dbName);
        query.executeUpdate();
    }

    public void deleteDbChangeLog(String customerId) {
        String id = "customerId";

        String queryStr = "delete from hive_dbs where hive_dbs.customer_id = :customerId";
        Query query = entityManager.createNativeQuery(queryStr);

        query.setParameter(id, customerId);
        query.executeUpdate();
    }
}
